package udf.matching;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

import org.apache.pig.EvalFunc;
import org.apache.pig.data.Tuple;
import org.apache.pig.data.TupleFactory;

import udf.contants.Contants;
import util.io.ReadFileInJAR;

/**
 * 
 * Receives:
 * 
 * Bag with tuples (suggestion ,rank) Gold query ()
 * 
 * @author sergio
 * 
 */
public class MatchQuerySuggestion extends EvalFunc<Tuple> {

	private int TOKEN_THRESHOLD = 3;  //greater or equal than this for approx matching
	private int DIFFERENCE_THRESHOLD=2;
	public boolean debug=false;
	/**
	 * 
	 * 
	 * 
	 * @param gold
	 * @param suggestion
	 * @return 
	 *
	 */
	
	
	
	private HashSet<String> stopWords = new HashSet<String>();

	public static  boolean invalidQueryReformulation(String query, String reformulation)
	{
		
		
		String q[] = query.split("\\s+");
		String ref[] = reformulation.split("\\s+");
		
		HashSet<String> r= new HashSet<String>();
	
		for(int i=0;i < ref.length; i++){
			
			r.add(ref[i]);
		}
		for(int i=0; i<q.length; i++){
			
			String token  = q[i];
			
			if(r.contains(token)){
				
				
				r.remove(token);
			}
		
			//if(r.contains(token + "s")){
			//	r.remove(token+ "s");
			
			
	//		}
		
			//if(token.length()>2)
		//	{
			//	String sub = token.substring(0, token.length()-1);
						
		//		if(r.contains(sub)){
							
			//	r.remove(sub);
			//	}
						
						
		//	}

		}
		if(r.size()==0) return true;
		
	/*	if(r.size()==1 ){
			
			Iterator<String> iter = r.iterator();
			String s = iter.next();
			
			
			if(s.length()==1) return true;
			
			
		}*/
		
		
		
		return false;
		
	}

	public MatchQuerySuggestion()  {
		for (int i = 0; i < Contants.stop_words_simple.length; i++) {
			stopWords.add(Contants.stop_words_simple[i].trim().toLowerCase());
		}

	}

	public int matchSuggestionApprox(String query, String gold,
			String suggestion) {

		// match if suggestion is a subset of golf
		gold = gold.replaceAll("\\s+", " ");
		
		query  = query.toLowerCase();
		gold = gold.toLowerCase();
		suggestion = suggestion.toLowerCase();

		
		
		if(matchSuggestionExact(query,gold,suggestion)==1) return 1;
		
		if(invalidQueryReformulation(query,gold)){
			
			return 0;
		}
		

		if (query.equals(suggestion)) {

			return 0;
		}

		if (query.equals(gold)) {

			return 0;
		}
		
		
		/*
		 * Clean tokens in reformulation (gold) that also appear in the original 
		 * query
		 * 
		 * buying animals    buying animals online
		 * 
		 * suggestion    buying animal 
		 * 
		 * 
		 */
		
		
			
		
		HashSet<String> tokens_in_query = new HashSet<String>();
		
		
		String tokens_query[] = query.split("\\s+");
	
			for (int j = 0; j < tokens_query.length; j++) {
					tokens_in_query.add(tokens_query[j]);

			}
		
			
			
			
		
		for(int i =0; i< tokens_query.length; i++){
			
			if(suggestion.equals(tokens_query[i])){
				
				
				return 0;
			}
		}
	//	if(suggestion.equals("free")){
			
			//debug=true;
			
			//System.out.println("no returning zero" + "\t"+);
			//System.out.println(suggestion+"\t"+ tokens_query + "\t"+ query);
		//}
		

		// some token in gold starts with a tpken in suggestio and suggestions is greater
		// than 3

		String temp[] = gold.split("\\s+");
		String sugg[] = suggestion.split("\\s+");

		for (int i = 0; i < temp.length; i++) {
			for (int j = 0; j < sugg.length; j++) {
				
			//	System.out.println(temp[i]+ "\t" + sugg);
				if (temp[i].equals(sugg[j]) &&  !tokens_in_query.contains(sugg[j]) && !stopWords.contains(sugg[j])) {
					
					if(debug)
					System.out.println("--\tquery:"  +query + "\tmatched:"+suggestion + "\t gold:"+ gold);
					return 1;
				}

				
				
				if ( substringApproxMatch(sugg[j],temp[i]) && !tokens_in_query.contains(sugg[j])  && temp[i].length() >= TOKEN_THRESHOLD
						&& sugg[j].length() >= TOKEN_THRESHOLD && !tokens_in_query.contains(temp[i])  && !stopWords.contains(sugg[j])) {
					
				//	System.out.println("APPROX 2 --\tquery:"  +query + "\t matched:"+suggestion +  "\t gold:"+ gold);
					
					
					if(debug)
					System.out.println("--\tquery:"  +query + "\t matched:"+suggestion +  "\t gold:"+ gold);
					return 1;
				}
			}
		}


		// token in suggestion

		// if (gold.contains(suggestion)) {

		// return 1;
		// }

	
		return 0;

	}

	
	
	
	
	public boolean substringApproxMatch(String gold, String token){
		
		
		String a=gold;
		String b=token;
		if (a.length()<b.length()){
			a=token;
			b=gold;
		}
		
		
		if(a.startsWith(b) || a.endsWith(b)){
			
			
			a= a.replace(b, "");
			if(a.length()<DIFFERENCE_THRESHOLD)  //the difference between the gold and token must bet at most two characters
				return true;
		}
		
		return false;
		
	}
	/*triggers true for cases like
	 * query    suggestion    gold
	 * 	game    games 		yahoo games
	 *  fac     faceb       facebook
	 * 
	 * 
	 * 
	 * 
	 * 
	 */
	public boolean singleTokenExceptions(String query, String suggestion,
			String gold) {
		
		
		

		if (gold.startsWith(suggestion)) {

			if (suggestion.length() > gold.length()) {

				suggestion = suggestion.replace(gold, "");

				if (suggestion.length() >= DIFFERENCE_THRESHOLD) {
					return true;

				}

			} else {

				gold = gold.replace(suggestion, "");

				if (gold.length() >= DIFFERENCE_THRESHOLD) {
					return true;

				}

			}

		}

		return false;

	}
	
	
	public String cleanStopWords(String a ){
		String c= "";
		
		a=a.replaceAll("\\s+", " ");
		String t[] = a.split("\\s+");
		
		for (int i =0; i<t.length;i++){
			
			if(!stopWords.contains(t[i].trim()))
				c = c + t[i]+" ";
		}
		return c.trim();
		
		
	}
	
	/**
	 * match if gold and sug
	 * 
	 * 
	 * @param gold
	 * @param suggestion
	 * @return
	 */
	public  int matchSuggestionExact(String query, String gold,
			String suggestion) {

		
		query  = query.toLowerCase();
		gold = gold.toLowerCase();
		suggestion = suggestion.toLowerCase();
		
		if(invalidQueryReformulation(query,gold)){
		
			return 0;
		}
		
		gold = gold.replaceAll("\\s+", " ");

		if (query.equals(suggestion)) {

			return 0;
		}
		
	

		// if query + suggestion = gold
		
		String temp = query + " " + suggestion;
		if (temp.equals(gold)) {
			if(debug)
			System.out.println("--\tquery:"  +query + "\tmatched:"+suggestion +  "\t gold:"+ gold);
			return 1;
		}

		temp = suggestion + " " + query;

		if (temp.equals(gold)) {
			if(debug)
			System.out.println("--\tquery:"  +query + "\tmatched:"+suggestion +  "\t gold:"+ gold);
			return 1;
		}

		if (gold.equals(suggestion)) {
			if(debug)
			System.out.println("--\tmatched:"+suggestion + "\t gold:"+ gold);
			return 1;
		}
	

		return 0;

	}

	public Tuple exec(Tuple input) throws IOException {

		if (input.size() != 3) {
			return null;
		}

		else {

			String query = (String) input.get(0);
			String gold = (String) input.get(1);
			String suggestion = (String) input.get(2);

			gold = gold.toLowerCase().trim();
			suggestion = suggestion.toLowerCase().trim();
			query = query.toLowerCase().trim();

			// exact and approximate match
			Tuple output = TupleFactory.getInstance().newTuple();

			int exact = matchSuggestionExact(query, gold, suggestion);

			int approx = 0;
			if (exact == 1) {

				approx = 1;
			} else {

				approx = matchSuggestionApprox(query, gold, suggestion);
			}

			output.append(Integer.valueOf(exact));
			output.append(Integer.valueOf(approx));

			return output;

		}

	}

	public static void main(String args[]) {
		String gold = "buenas buenas1";
		String ref="buenas buenas1s 1";
		System.out.println(invalidQueryReformulation(gold,ref));

	}

}
